/*
* 讯飞自动转换(iFly Auto Transform)功能可以实时将语音转换为对应的文字。
*/

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <errno.h>
#include <process.h>

#include "msp_cmn.h"
#include "msp_errors.h"
#include "./include/speech_recognizer.h"

#pragma warning(disable:4996)

#define FRAME_LEN    640 
#define BUFFER_SIZE  4096

enum {
    EVT_START = 0,
    EVT_STOP,
    EVT_QUIT,
    EVT_TOTAL
};

static HANDLE events[EVT_TOTAL] = { NULL, NULL, NULL };

//static COORD begin_pos = { 0, 0 };
//static COORD last_pos = { 0, 0 };
//
//static void show_result(char* string, char is_over)
//{
//    COORD orig, current;
//    CONSOLE_SCREEN_BUFFER_INFO info;
//    HANDLE w = GetStdHandle(STD_OUTPUT_HANDLE);
//    GetConsoleScreenBufferInfo(w, &info);
//    current = info.dwCursorPosition;
//
//    if (current.X == last_pos.X && current.Y == last_pos.Y) {
//        SetConsoleCursorPosition(w, begin_pos);
//    }
//    else {
//        /* changed by other routines, use the new pos as start */
//        begin_pos = current;
//    }
//    if (is_over)
//        SetConsoleTextAttribute(w, FOREGROUND_GREEN);
//    printf("Result: [ %s ]\n", string);
//    if (is_over)
//        SetConsoleTextAttribute(w, info.wAttributes);
//
//    GetConsoleScreenBufferInfo(w, &info);
//    last_pos = info.dwCursorPosition;
//}
//
//static void show_key_hints(void)
//{
//    printf("\n\
//----------------------------\n\
//Press r to start speaking\n\
//Press s to end your speaking\n\
//Press q to quit\n\
//----------------------------\n");
//}

/* helper thread: to listen to the keystroke */
//static unsigned int __stdcall helper_thread_proc(void* para)
//{
//    int key;
//    int quit = 0;
//
//    do {
//        key = _getch();
//        switch (key) {
//        case 'r':
//        case 'R':
//            SetEvent(events[EVT_START]);
//            break;
//        case 's':
//        case 'S':
//            SetEvent(events[EVT_STOP]);
//            break;
//        case 'q':
//        case 'Q':
//            quit = 1;
//            SetEvent(events[EVT_QUIT]);
//            PostQuitMessage(0);
//            break;
//        default:
//            break;
//        }
//
//        if (quit)
//            break;
//    } while (1);
//
//    return 0;
//}

//static HANDLE start_helper_thread()
//{
//    HANDLE hdl;
//
//    hdl = (HANDLE)_beginthreadex(NULL, 0, helper_thread_proc, NULL, 0, NULL);
//
//    return hdl;
//}

static char* g_result = NULL;
static unsigned int g_buffersize = BUFFER_SIZE;

void on_result(const char* result, char is_last)
{
    if (result) {
        size_t left = g_buffersize - 1 - strlen(g_result);
        size_t size = strlen(result);
        if (left < size) {
            g_result = (char*)realloc(g_result, g_buffersize + BUFFER_SIZE);
            if (g_result)
                g_buffersize += BUFFER_SIZE;
            else {
                printf("mem alloc failed\n");
                return;
            }
        }
        strncat(g_result, result, size);
       // show_result(g_result, is_last);
    }
}

void on_speech_begin()
{
    if (g_result) {
        free(g_result);
    }
    g_result = (char*)malloc(BUFFER_SIZE);
    g_buffersize = BUFFER_SIZE;
    memset(g_result, 0, g_buffersize);

    printf("Start Listening...\n");
}

void on_speech_end(int reason)
{
    if (reason == END_REASON_VAD_DETECT)
        printf("\nSpeaking done \n");
    else
        printf("\nRecognizer error %d\n", reason);
}

/* demo recognize the audio from microphone */
static void demo_mic(const char* session_begin_params)
{
    int errcode;
    int i = 0;
    HANDLE helper_thread = NULL;

    struct speech_rec iat;
    DWORD waitres;
    char isquit = 0;

    struct speech_rec_notifier recnotifier = {
        on_result,
        on_speech_begin,
        on_speech_end
    };

    errcode = sr_init(&iat, session_begin_params, SR_MIC, DEFAULT_INPUT_DEVID, &recnotifier);
    if (errcode) {
        printf("speech recognizer init failed\n");
        return;
    }

    for (i = 0; i < EVT_TOTAL; ++i) {
        events[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
    }

    helper_thread = start_helper_thread();
    if (helper_thread == NULL) {
        printf("create thread failed\n");
        goto exit;
    }

    show_key_hints();

    while (1) {
        waitres = WaitForMultipleObjects(EVT_TOTAL, events, FALSE, INFINITE);
        switch (waitres) {
        case WAIT_FAILED:
        case WAIT_TIMEOUT:
            printf("Why it happened !?\n");
            break;
        case WAIT_OBJECT_0 + EVT_START:
            if (errcode = sr_start_listening(&iat)) {
                printf("start listen failed %d\n", errcode);
                isquit = 1;
            }
            break;
        case WAIT_OBJECT_0 + EVT_STOP:
            if (errcode = sr_stop_listening(&iat)) {
                printf("stop listening failed %d\n", errcode);
                isquit = 1;
            }
            break;
        case WAIT_OBJECT_0 + EVT_QUIT:
            sr_stop_listening(&iat);
            isquit = 1;
            break;
        default:
            break;
        }
        if (isquit)
            break;
    }

exit:
    if (helper_thread != NULL) {
        WaitForSingleObject(helper_thread, INFINITE);
        CloseHandle(helper_thread);
    }

    for (i = 0; i < EVT_TOTAL; ++i) {
        if (events[i])
            CloseHandle(events[i]);
    }

    sr_uninit(&iat);
}

/* main thread: start/stop record ; query the result of recognition.
 * record thread: record callback(data write)
 * helper thread: ui(keystroke detection)
 */
char * sound_to_str()
{
    int ret = MSP_SUCCESS;
    const char* login_params = "appid = 02fca5ca, work_dir = ."; // 登录参数，appid和msc工作目录
    int aud_src = 0;
    SetConsoleOutputCP(936);

    /*
    * sub:                业务类型
    * domain:             领域
    * language:           语言
    * accent:             方言
    * sample_rate:        音频采样率
    * result_type:        识别结果类型
    * result_encoding:    结果编码格式
    *
    */
    const char* session_begin_params = "sub = iat, domain = iat, language = zh_cn, accent = mandarin, sample_rate = 16000, result_type = plain, result_encoding = gb2312";

    /* 用户登录 */
    ret = MSPLogin(NULL, NULL, login_params); // 第一个参数为用户名，第二个参数为密码，传入NULL即可，第三个参数为登录参数
    if (MSP_SUCCESS != ret) {
        printf("MSPLogin failed , Error code %d.\n", ret);
    }
    demo_mic(session_begin_params);
    MSPLogout(); // 退出登录
    return g_result;
}